接續實作-商品系統(三)-訂單列表及訂購商品部分(一),我們將完成訂單列表及訂購商品部分
的開發。
新增的部分:
.
├── app.js
├── bin
│ └── www
├── config
│ └── development_config.js
├── controllers
│ ├── member
│ │ └── modify_controller.js
│ ├── order
│ │ ├── get_controller.js
│ │ └── modify_controller.js
│ ├── product
│ │ └── get_controller.js
├── models
│ ├── member
│ │ ├── encryption_model.js
│ │ ├── login_model.js
│ │ ├── register_model.js
│ │ ├── update_model.js
│ │ └── verifyication_model.js
│ ├── order
│ │ ├── all_order_model.js
│ │ └── order_all_product_model.js
│ ├── product
│ │ └── all_product.js
│ └── connection_db.js
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes
│ ├── member.js
│ ├── order.js
│ └── product.js
├── sevice
│ └── member_check.js
├── views
├── error.ejs
└── index.ejs
├── .env
└── .gitignore
接續我們剩下訂單列表(GET)
及進行訂購(POST)
的部分。我們先來實作進行訂購(POST)
的功能,因為若先做完訂單列表(GET)
功能,我們並沒有資料可以來測試這部分(笑)。
筆者將這支API預設為client端需要輸入的資料為:
在這當中,較為特殊的是productID
及quantity
之間的關係,而它們之間的關係等同於假設有一筆訂單,會員買了商品編號1及商品編號2的東西,且各自的數量依序為3個及4個。這時,前端開發的夥伴只要將資料整理成上述情況,當我們server端接收到後,將資料切割成一個object
的形式:
obejct {
1: 3,
2: 4
}
接續使用for迴圈
的方式,依序將訂單資料存入資料庫中。這種設計方式是為了因應在實作-商品系統(二)-資料庫設計所提到的order_list
部分的資料欄位設計:
order_id | customer_id | product_id | order_quantity | order_price | is_complete | create_date | update_date |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 2 | 24.00 | 0 | 2018-01-05 | datetime |
1 | 1 | 2 | 1 | 5.00 | 0 | 2018-01-05 | datetime |
1 | 1 | 3 | 1 | 20.00 | 0 | 2018-01-05 | datetime |
等同於假設會員1買了三樣物品,在範例中分別是商品編號1、商品編號2及商品編號3的東西。且這三樣物品都算是同一筆訂單的設計方式。
為了做到這個方式,首先我們先處理models
> order
資料夾的order_all_product_model.js
檔案:
但在撰寫處理這部分時,我們會先碰到兩個問題:
order_id當初在建立資料庫時不是使用AUTO_INCREMENT
,也就是不會自行新增order_id的編號。(當然,這部分是故意的,因為假如我們使用了自動新增編號的功能,代表我們沒辦法達到上述的table設計。)
商品沒有夾帶自身價格,等同於我們還要額外去product
的table去撈商品價格,這樣才能計算order_price
的價格。
這部分我們可以透過資料庫的MAX()
方式來幫我們找出最大值:
// 取得訂單id
const getOrderID = () => {
return new Promise((resolve, reject) => {
db.query('SELECT MAX(order_id) AS id FROM order_list', function (err, rows, fields) {
if (err) {
console.log(err);
reject(err);
return;
}
resolve(rows[0].id);
})
})
}
待取得後,等等在主要的function
中,我們接續在幫該值+1就能取得新的order_id
值了。
這部分因為我們在要求client端將資料傳過來時的productID
剛好就是product
table本身各個商品的id
。所以這時只要將該值帶進入資料庫進行SELECT
動作就能在取到個別商品的價格:
// 取得商品價格
const getProductPrice = (productID) => {
return new Promise((resolve, reject) => {
db.query('SELECT price FROM product WHERE id = ?', productID, function (err, rows) {
if (err) {
console.log(err);
reject(err);
return;
}
resolve(rows[0].price);
})
})
}
這部分就將我們剛剛額外撰寫的兩個funciton
放置其中,並處理一開始所提到將client端輸入的資料進行切分,轉變成object
的型態,並將資料帶入到table中:
const db = require('../connection_db');
module.exports = function orderProductListData(orderList) {
//訂購整筆商品
let result = {};
return new Promise(async (resolve, reject) => {
// 提取orderID
let orderID = await getOrderID() + 1;
const products = orderList.productID;
const productArray = products.split(',');
// console.log("productArray: " + productArray);
const quantitys = orderList.quantity;
const quantityArray = quantitys.split(',');
// console.log("quantityArray: " + quantityArray);
//productID與quantity合併成新object
//array1 [3, 2, 1]
//array2 [1, 2, 3]
//merge為object:{
// 3: 1,
// 2: 2,
// 1, 3
//}
let productQuantity = {};
for (let i in productArray) {
// console.log('productArray i: ' + productArray[i]);
let index = productArray.indexOf(productArray[i]);
// console.log('the index: ' + index);
for (let j in quantityArray) {
// console.log('quantityArray j: ' + quantityArray[j]);
productQuantity[productArray[i]] = quantityArray[index];
// console.log('new quantityArray j: ' + quantityArray[index]);
}
}
let orderAllData = [];
for (let key in productQuantity) {
// console.log(orderID);
const price = await (getProductPrice(key));
const orderData = {
order_id: orderID,
member_id: orderList.memberID,
product_id: key,
order_quantity: parseInt(productQuantity[key]),
order_price: parseInt(price) * parseInt(productQuantity[key]),
order_date: orderList.orderDate,
is_complete: 0
};
// insert order data.
db.query('INSERT INTO order_list SET ?', orderData, function (err, rows) {
if (err) {
console.log(err);
result.err = "伺服器錯誤,請稍後在試!"
reject(result);
return;
}
})
orderAllData.push(orderData);
}
result.state = "訂單建立成功。";
result.orderData = orderAllData
resolve(result);
})
}
由於model
部分的設置已經結束,接續我們到controllers
> order
資料夾的modify_controller.js
來寫入判斷是否為會員及匯入剛剛所撰寫的model
部分的程式:
const Check = require('../../service/member_check');
const verify = require('../../models/member/verification_model');
const orderProductListData = require('../../models/order/order_all_product_model');
check = new Check();
module.exports = class ModifyOrder {
// 訂整筆訂單
postOrderAllProduct(req, res, next) {
const token = req.headers['token'];
//確定token是否有輸入
if (check.checkNull(token) === true) {
res.json({
err: "請輸入token!"
})
} else if (check.checkNull(token) === false) {
verify(token).then(tokenResult => {
if (tokenResult === false) {
res.json({
result: {
status: "token錯誤。",
err: "請重新登入。"
}
})
} else {
const memberID = tokenResult;
const orderList = {
memberID: memberID,
productID: req.body.productID,
quantity: req.body.quantity,
orderDate: onTime(),
}
orderProductListData(orderList).then(result => {
res.json({
result: result
})
}, (err) => {
res.json({
result: err
})
})
}
})
}
}
}
//取得現在時間,並將格式轉成YYYY-MM-DD HH:MM:SS
const onTime = () => {
const date = new Date();
const mm = date.getMonth() + 1;
const dd = date.getDate();
const hh = date.getHours();
const mi = date.getMinutes();
const ss = date.getSeconds();
return [date.getFullYear(), "-" +
(mm > 9 ? '' : '0') + mm, "-" +
(dd > 9 ? '' : '0') + dd, " " +
(hh > 9 ? '' : '0') + hh, ":" +
(mi > 9 ? '' : '0') + mi, ":" +
(ss > 9 ? '' : '0') + ss
].join('');
}
再來,設置個API URL給這部分的功能。至routes
資料夾的order.js
檔案中:
var express = require('express');
var router = express.Router();
const OrderModifyMethod = require('../controllers/order/modify_controller');
orderModifyMethod = new OrderModifyMethod();
// 訂整筆訂單
router.post('/order', orderModifyMethod.postOrderAllProduct);
module.exports = router;
最後,別忘了app.js
檔案也要寫入:
const order = require('./routes/order.js');
app.use('/', order);
這部分我們透過Postman來進行測試:
HTTP method: POST
HTTP url : localhost:3000/order
Body中選擇x-www-form-urlencoded
headers
body
其結果:
這部分所需要做的事情就單純許多,只要去order_list
的table中,將整個訂單資料撈出來就可以了。
先到models
> order
資料夾的all_order_model.js
,並輸入:
const db = require('../connection_db');
module.exports = function getAllOrderData() {
let result = {};
return new Promise((resolve, reject) => {
db.query('SELECT * FROM order_list', function (err, rows) {
// 若資料庫部分出現問題,則回傳「伺服器錯誤,請稍後再試!」的結果。
if (err) {
console.log(err);
result.status = "取得全部訂單資料失敗。"
result.err = "伺服器錯誤,請稍後在試!"
reject(result);
return;
}
// 若資料庫部分沒問題,則回傳全部訂單資料。
resolve(rows);
})
})
}
之後到controllers
> order
資料夾的get_controller.js
檔案,來把model
及辨識會員部分匯入進去:
const Check = require('../../service/member_check');
const verify = require('../../models/member/verification_model');
const orderData = require('../../models/order/all_order_model');
check = new Check();
module.exports = class GetOrder {
// 取得全部訂單資料
getAllOrder(req, res, next) {
const token = req.headers['token'];
//確定token是否有輸入
if (check.checkNull(token) === true) {
res.json({
err: "請輸入token!"
})
} else if (check.checkNull(token) === false) {
verify(token).then(tokenResult => {
if (tokenResult === false) {
res.json({
result: {
status: "token錯誤。",
err: "請重新登入。"
}
})
} else {
orderData().then(result => {
res.json({
result: result
})
}, (err) => {
res.json({
result: err
})
})
}
})
}
}
}
最後,再給該功能一個API URL。到routes
資料夾的order.js
檔案中寫入:
var express = require('express');
var router = express.Router();
const OrderGetMethod = require('../controllers/order/get_controller');
const OrderModifyMethod = require('../controllers/order/modify_controller');
orderGetMethod = new OrderGetMethod();
orderModifyMethod = new OrderModifyMethod();
// 取得全部訂單資料
router.get('/order', orderGetMethod.getAllOrder);
// 訂整筆訂單
router.post('/order', orderModifyMethod.postOrderAllProduct);
module.exports = router;
依舊使用Postman來進行測試:
HTTP method: GET
HTTP url : localhost:3000/order
headers
其結果:
在這階段我們已經完成訂單列表及訂購商品部分
的三支API,而下個章節將接續開發修改訂單部分
的功能。